package com.lingjtx.common.core.algorithm;

import com.lingjtx.common.core.constant.Const;
import com.lingjtx.common.core.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RSAUtil {

    private static final Logger log = LoggerFactory.getLogger(RSAUtil.class);

    /**
     * 生成密钥对
     *
     * @return 密钥对对象
     */
    public static KeyStore createKeys() {
        //KeyPairGenerator用于生成公钥和私钥对。密钥对生成器是使用 getInstance 工厂方法
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(2048);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            PrivateKey privateKey = keyPair.getPrivate();
            PublicKey publicKey = keyPair.getPublic();
            return new KeyStore(publicKey, privateKey);
        } catch (NoSuchAlgorithmException e) {
            log.error("生成密钥对异常{}", e.getMessage());
            return null;
        }
    }

    /**
     * RSA 公钥加密
     *
     * @param data   加密数据
     * @param pubKey 公钥
     * @return 加密后的值
     */
    public static String encrypt(String data, String pubKey) {
        if (StringUtil.isEmpty(data) || StringUtil.isEmpty(pubKey)) return null;
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            //初始化公钥,根据给定的编码密钥创建一个新的 X509EncodedKeySpec。
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(pubKey));
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            //数据加密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes()));
        } catch (Exception e) {
            log.error("RSA 加密异常{}", e.getMessage());
            return null;
        }
    }

    /**
     * RSA私钥解密
     *
     * @param value  RSA加密后的值
     * @param priKey 私钥
     * @return 解密后的值
     */
    public static String decrypt(String value, String priKey) {
        if (StringUtil.isEmpty(value) || StringUtil.isEmpty(priKey)) return null;
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(priKey));
        try {
            PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec);
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] b = Base64.getDecoder().decode(value);
            return new String(cipher.doFinal(b));
        } catch (Exception e) {
            log.error("RSA 解密异常{}", e.getMessage());
            return null;
        }
    }

    public static String encryptByDefaultKey(String val) {
        return encrypt(val, Const.RSA_PUB_KEY);
    }

    public static String decryptByDefaultKey(String val) {
        return decrypt(val, Const.RSA_PRI_KEY);
    }

    public static String sign(String plainText, String priKey) {
        try {
            PrivateKey key = loadPrivateKey(priKey);
            // 签名方式（固定SHA256withRSA）
            Signature sign = Signature.getInstance("SHA256withRSA");
            // 使用私钥进行初始化签名（私钥需要从私钥文件【证书】中读取）
            sign.initSign(key);
            // 签名更新
            sign.update(plainText.getBytes());
            // 对签名结果进行Base64编码
            return Base64.getEncoder().encodeToString(sign.sign());
        } catch (Exception e) {
            log.error("SHA256withRSA signature error:{}", e.getMessage());
            return null;
        }
    }

    // 验签客户端保存私钥，服务端保存公钥
    public static boolean verify(String data, String signature, String publicKey) {
        try {
            PublicKey key = loadPublicKey(publicKey);
            Signature rsa = Signature.getInstance("SHA256withRSA");
            rsa.initVerify(key);
            rsa.update(data.getBytes(StandardCharsets.UTF_8));
            byte[] signatureBytes = Base64.getDecoder().decode(signature);
            return rsa.verify(signatureBytes);
        } catch (Exception e) {
            log.error("SHA256withRSA verify error:{}", e.getMessage());
            return false;
        }
    }

    public static PrivateKey loadPrivateKey(String priKey) {
        try {
            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(priKey)));
        } catch (NoSuchAlgorithmException var2) {
            throw new RuntimeException("当前Java环境不支持RSA", var2);
        } catch (InvalidKeySpecException var3) {
            throw new RuntimeException("无效的密钥格式");
        }
    }

    public static PublicKey loadPublicKey(String pubKey) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            //初始化公钥,根据给定的编码密钥创建一个新的 X509EncodedKeySpec。
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(pubKey));
            return keyFactory.generatePublic(x509EncodedKeySpec);
        } catch (NoSuchAlgorithmException var2) {
            throw new RuntimeException("当前Java环境不支持RSA", var2);
        } catch (InvalidKeySpecException var3) {
            throw new RuntimeException("无效的密钥格式");
        }
    }
}
